package com.xzc.one.common.pay.alipay;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author xiongzhicong
 * @create 2019-11-10 12:57
 **/
@Data
@Component
@ConfigurationProperties(prefix = "pay.alipay")
public class AliPay {

    private String gatewayUrl;//支付宝gatewayUrl
    private String appId;//商户应用id
    private String privateKey;//RSA私钥，用于对商户请求报文加签
    private String publicKey;//支付宝RSA公钥，用于验签支付宝应答
    private String signType = "RSA2";//签名类型
    private String formate = "json";//格式
    private String charset = "UTF-8";//编码
    private String timeoutExpress = "1h";//该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。
    // m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。
    // 该参数数值不接受小数点， 如 1.5h，可转换为 90m。注：若为空，则默认为15d。
    private final String productCode = "QUICK_MSECURITY_PAY";
    private String returnUrl;//同步地址
    private String notifyUrl;//异步地址
    private final int maxQueryRetry = 5;//最大查询次数
    private final long queryDuration = 5000;//查询间隔（毫秒）
    private final int maxCancelRetry = 3;//最大撤销次数
    private final long cancelDuration = 3000;//撤销间隔（毫秒
    private AlipayClient alipayClient;

    @PostConstruct
    public void aaa() {
        StringBuilder sb = new StringBuilder("\nConfigs{");
        sb.append("支付宝网关: ").append(gatewayUrl).append(",\n");
        sb.append("appId: ").append(appId).append(",\n");
        sb.append("商户RSA私钥: ").append(privateKey).append(",\n");
        sb.append("支付宝RSA公钥: ").append(publicKey).append(",\n");
        sb.append("签名类型: ").append(signType).append(",\n");
        sb.append("查询重试次数: ").append(maxQueryRetry).append(",\n");
        sb.append("查询间隔(毫秒): ").append(queryDuration).append(",\n");
        sb.append("撤销尝试次数: ").append(maxCancelRetry).append(",\n");
        sb.append("撤销重试间隔(毫秒): ").append(cancelDuration).append(",\n");
        sb.append("}\n");
        System.out.println(sb.toString());
        //throw new GlobalException(CodeMsg.TRAD_ERROR);
    }

    /**
     * alipay-sdk-java
     */
    public AliPay() {
        alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, formate, charset, publicKey, signType);
    }

    /**
     * @param body   对一笔交易的具体描述信息。如果是多种商品，请将商品描述字符串累加传给body。
     * @param no     商户网站唯一订单号
     * @param amount 订单总金额，单位为元，精确到小数点后两位，取值范围[0.01,100000000]
     * @return String
     */
    public String creatPcOrder(String body, String no, int amount) {
        String strAmount = String.format("%.2f", new BigDecimal(amount).divide(new BigDecimal(100)));
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        model.setBody(body);
        model.setSubject(body);//商品的标题/交易标题/订单标题/订单关键字等。
        model.setOutTradeNo(no);
        model.setTimeoutExpress(timeoutExpress);
        model.setTotalAmount(strAmount);
        model.setProductCode(productCode);
        request.setBizModel(model);
        request.setNotifyUrl(notifyUrl);
        AlipayTradePrecreateResponse response = null;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return null;
        }
        if (response.isSuccess()) {
            System.out.println("调用成功");
            return response.getQrCode();
        } else {
            System.out.println("调用失败");
        }
        return null;
    }

    /**
     * 支付宝下单
     *
     * @param body   描述
     * @param no     编号
     * @param amount 金额
     */
    public String creatAppOrder(String body, String no, int amount) {
        String strAmount = String.format("%.2f", new BigDecimal(amount).divide(new BigDecimal(100)));
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(body);
        model.setSubject(body);
        model.setOutTradeNo(no);
        model.setTimeoutExpress(timeoutExpress);
        model.setTotalAmount(strAmount);
        model.setProductCode(productCode);
        request.setBizModel(model);
        request.setNotifyUrl(notifyUrl);
        AlipayTradeAppPayResponse response = null;
        try {
            response = alipayClient.sdkExecute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return null;
        }
        if (response.isSuccess()) {
            System.out.println("调用成功");
            return response.getBody();
        } else {
            System.out.println("调用失败");
        }
        return null;
    }

    /**
     * 支付回调解密
     *
     * @param requestParams
     * @return boolean
     */
    public boolean checkCallBack(Map<String, String[]> requestParams) {
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");//乱码解决，这段代码在出现乱码时使用。
            params.put(name, valueStr);
        }
//切记publickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        try {
            return AlipaySignature.rsaCheckV1(params, publicKey, charset, signType);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 取消订单（已支付的订单则退还金额）
     *
     * @param no 订单编号
     * @return boolean
     */
    public boolean cancelOrder(String no) {
        AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
        request.setBizContent("{\"out_trade_no\":\"" + no + "\"}");
        AlipayTradeCancelResponse response = null;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return false;
        }
        if (response.isSuccess()) {
            System.out.println("调用成功");
            return true;
        } else {
            System.out.println("调用失败");
        }
        return false;
    }

    /**
     * 订单退款（全额退款、部分退款）
     *
     * @param no       订单编号
     * @param amount   订单金额（分）
     * @param reason   退款原因
     * @param refondNo 退款单号
     * @return boolean
     */
    public boolean refound(String no, Integer amount, String reason, String refondNo) {
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        String strAmount = String.format("%.2f", new BigDecimal(amount).divide(new BigDecimal(100)));
        reason = (reason == null || reason.isEmpty() ? "正常退款" : reason);
        request.setBizContent("{" +
                "\"out_trade_no\":\"" + no + "\"," +
                //"\"trade_no\":\"2014112611001004680073956707\"," +
                "\"refund_amount\":" + strAmount + "," +
                "\"refund_reason\":\"" + reason + "\"," +
                "\"out_request_no\":\"" + refondNo + "\"" +
                //"\"operator_id\":\"OP001\"," +
                //"\"store_id\":\"NJ_S_001\"," +
                //"\"terminal_id\":\"NJ_T_001\"" +
                "  }");
        AlipayTradeRefundResponse response = null;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return false;
        }
        if (response.isSuccess()) {
            System.out.println("调用成功");
            return true;
        } else {
            System.out.println("调用失败");
        }
        return false;
    }

    /**
     * 订单退款（全额退款、部分退款）
     *
     * @param no       订单编号
     * @param amount   订单金额（分）
     * @param reason   退款原因
     * @param refondNo 退款单号
     * @return map
     */
    public Map<String, String> orderRefund(String no, Integer amount, String reason, String refondNo) {
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        String strAmount = String.format("%.2f", new BigDecimal(amount).divide(new BigDecimal(100)));
        reason = (reason == null || reason.isEmpty() ? "正常退款" : reason);
        request.setBizContent("{" +
                "\"out_trade_no\":\"" + no + "\"," +
                //"\"trade_no\":\"2014112611001004680073956707\"," +
                "\"refund_amount\":" + strAmount + "," +
                "\"refund_reason\":\"" + reason + "\"," +
                "\"out_request_no\":\"" + refondNo + "\"" +
                //"\"operator_id\":\"OP001\"," +
                //"\"store_id\":\"NJ_S_001\"," +
                //"\"terminal_id\":\"NJ_T_001\"" +
                "  }");
        AlipayTradeRefundResponse response = null;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return null;
        }
        if (response.isSuccess()) {
            Map<String, String> map = new HashMap<>();
            map.put("out_trade_no", no);
            map.put("out_refund_no", refondNo);
            map.put("total_fee", strAmount);
            map.put("refund_fee", strAmount);
            return map;
        } else {
            System.out.println("调用失败");
        }
        return null;
    }

    /**
     * 支付结果查询
     *
     * @param no
     * @return String
     * @throws Exception
     */
    public String queryOrder(String no) {
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizContent("{\"out_trade_no\":\"" + no + "\"" +
                //"\"trade_no\":\"2014112611001004680073956707\"" +
                "}");
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return null;
        }
        if (response.isSuccess()) {
            System.out.println("调用成功");
            return response.getTradeStatus();
        } else {
            System.out.println("调用失败");
        }
        return null;
    }

    public enum AliPayResult {
        WAIT_BUYER_PAY("交易创建，等待买家付款", "WAIT_BUYER_PAY"),
        TRADE_CLOSED("未付款交易超时关闭，或支付完成后全额退款", "TRADE_CLOSED"),//退款到银行发现用户的卡作废或者冻结了，导致原路退款银行卡失败，可前往商户平台（pay.weixin.qq.com）-交易中心，手动处理此笔退款。$n为下标，从0开始编号。
        TRADE_SUCCESS("交易支付成功", "TRADE_SUCCESS"),
        TRADE_FINISHED("交易结束，不可退款", "TRADE_FINISHED");
        private String name;
        private String value;

        AliPayResult(String name, String value) {
            this.name = name;
            this.value = value;
        }

        public String getName() {
            return name;
        }

        public String getValue() {
            return value;
        }
    }
}